#pragma once
#include <iostream>
#include <cstring>
#include <unordered_map>
#include <memory>
#include "Connection.hpp"
#include "Epoller.hpp"

// class Connection;

// 底层是使用epoll，暂时称做TcpServer
class Reactor
{
    static const int gnum = 64;

public:
    Reactor() : _epoller(std::make_unique<Epoller>()), _isrunning(false)
    {
    }

    void AddConnection(int fd, uint32_t events, const InetAddr &addr, int type) // 稍后再调整
    {
        // 1.构建一个connection
        Connection *conn = new Connection(fd);
        conn->SetEvents(events);
        conn->SetConnectionType(type);
        conn->SetAddr(addr);

        // 将当前对象，设置进入所有的conn对象中
        conn->SetReactor(this);

        // TODO, 设置对connection的上层处理， 即， 如果该connection就绪被激活，该如何处理？
        if (conn->Type() == ListenConnection)
        {
            conn->RegisterHandler(_OnConnect, nullptr, nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRecver, _OnSender, _OnExcepter);
        }

        // 2.fd和events写透到OS中，托管给epoll
        if (!_epoller->AddEvent(conn->Sockfd(), conn->Events()))
            return;

        // 3.托管给_connection
        _connections.insert(std::make_pair(fd, conn));
    }

    // 开启连接对于读写事件的关心
    void EnableConnectionReadWrite(int sockfd, bool readable, bool writable)
    {
        if (!IsConnectionExist(sockfd))
        {
            return;
        }

        uint32_t events = (readable ? EPOLLIN : 0) | (writable ? EPOLLOUT : 0) | EPOLLET;
        _connections[sockfd]->SetEvents(events);

        // 将关心的事件写透内核里，因此使用epoller
        _epoller->ModEvent(_connections[sockfd]->Sockfd(), _connections[sockfd]->Events());
    }

    void DelConnection(int sockfd)
    {
        // 0. 安全检查
        if (!IsConnectionExist(sockfd))
        {
            return;
        }
        LOG(INFO, "sockfd quit, 服务器释放所有资源\n", sockfd);
        // 1.在内核中移除对sockfd的关心（epoll当中去掉事件关心
        EnableConnectionReadWrite(sockfd, false, false);
        // 1.1再从epoll中删除掉这个fd
        _epoller->DelEvent(sockfd);
        // 2.关闭sockfd
        _connections[sockfd]->Close();
        // 3.在Reactor中移除对Connection的关心
        delete _connections[sockfd];
        _connections.erase(sockfd);
    }

    // 用于检测获取一次已经就绪的事件
    void LoopOnce(int timeout)
    {
        // 从epoll获取就绪事件
        int n = _epoller->Wait(revs, gnum, timeout);
        // 只有n > 0才会处理，所以不用再判断n
        for (int i = 0; i < n; i++)
        {
            int sockfd = revs[i].data.fd;
            uint32_t revents = revs[i].events;
            // 将epoll发生的错误或挂断，让这些事件全部放在读写事件就绪中延迟处理
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN) //
            {
                if (IsConnectionExist(sockfd) && _connections[sockfd]->_handler_recver)
                {
                    // 读事件就绪，派发给对应的connection
                    _connections[sockfd]->_handler_recver(_connections[sockfd]);
                }
            }
            if (revents & EPOLLOUT)
            {
                if (IsConnectionExist(sockfd) && _connections[sockfd]->_handler_sender)
                {
                    // 写事件就绪，派发给对应的connection
                    _connections[sockfd]->_handler_sender(_connections[sockfd]);
                }
            }
        }
    }

    // 对于服务器来讲，只知道自己在管理connection
    void Dispatcher() // 改为事件派发
    {
        int timeout = -1; // 非阻塞
        _isrunning = true;
        while (true)
        {
            LoopOnce(timeout);
            PrintDebug();
        }
        _isrunning = false;
    }

    bool IsConnectionExist(int sockfd)
    {
        // 判断一个sockfd是否存在于connections(哈希表)当中
        return _connections.find(sockfd) != _connections.end();
    }
    void SetOnConnect(handler_t OnConnect)
    {
        _OnConnect = OnConnect;
    }
    void SetOnNormalHandler(handler_t recver, handler_t sender, handler_t excepter)
    {
        _OnRecver = recver;
        _OnSender = sender;
        _OnExcepter = excepter;
    }
    void PrintDebug()
    {
        std::string fdlist;
        for (auto &conn : _connections)
        {
            fdlist += std::to_string(conn.second->Sockfd()) + " ";
        }

        LOG(DEBUG, "epoll管理的fd列表: %s\n", fdlist.c_str());
    }
    ~Reactor() {}

private:
    //  使用TcpServer将所有的connections管理起来
    //  key: sockfd
    //  value: Connection*
    //  优势：能够很快的通过文件描述符，来找到connection对象，在未来高效执行connection对应的处理事件的方法
    std::unordered_map<int, Connection *> _connections;

    std::unique_ptr<Multiplex> _epoller;
    // 判断服务器是否开启
    bool _isrunning;

    struct epoll_event revs[gnum];

public:
    // Reactor中添加处理sockfd的方法集
    // 1.处理新连接到来
    handler_t _OnConnect;
    // 2.处理普通sockfd，主要是IO处理
    handler_t _OnRecver;
    handler_t _OnSender;
    handler_t _OnExcepter;
};